﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using GersonFrame.Tool;

namespace GersonFrame
{


    public enum GuideType
    {
        Rect,
        Cycle,
    }


    [RequireComponent(typeof(CycleGuide))]
    [RequireComponent(typeof(RectGuide))]
    public class GuideManager : MonoBehaviour, ICanvasRaycastFilter
    {

        private static GuideManager m_instance;
        public static GuideManager Instance
        {
            get
            {
                return m_instance;
            }
        }
        /// <summary>
        /// 圆形引导
        /// </summary>
        private CycleGuide m_cycleGuide;
        /// <summary>
        ///矩形引导
        /// </summary>
        private RectGuide m_rectGuide;
        public System.Action m_OnFinished;

        public Vector3 Center
        {
            get
            {
                switch (m_currentGuideType)
                {
                    case GuideType.Rect:
                        return this.m_rectGuide.Center;
                    case GuideType.Cycle:
                        return this.m_cycleGuide.Center;
                    default:
                        MyDebuger.LogError("Can not found Guidetype " + this.m_currentGuideType);
                        return this.m_rectGuide.Center;
                }
            }
        }

        /// <summary>
        /// 圆形材质
        /// </summary>
        public Material m_cycleMat;
        /// <summary>
        /// 矩形材质
        /// </summary>
        public Material m_rectMat;
        /// <summary>
        /// 遮罩
        /// </summary>
        private Image m_maskImg;
        /// <summary>
        /// 当前步骤目标
        /// </summary>
        private RectTransform m_targetRect;

        /// <summary>
        /// 新手引导Canvas
        /// </summary>
        private Canvas m_canvas;
        public BaseStep[] m_AllSteps;
        private int m_currentStepIndex = 0;
        private GuideType m_currentGuideType = GuideType.Rect;
        private bool m_hasexcuted = true;

        private void Awake()
        {
            m_instance = this;
            this.m_maskImg = transform.GetComponent<Image>();
            if (this.m_maskImg == null)
                throw new System.Exception("自身组件中未包含 Mask");
            if (this.m_rectMat == null || this.m_cycleMat == null)
                throw new System.Exception("材质未赋值");
            //初始化引导形状信息
            this.m_cycleGuide = this.GetComponent<CycleGuide>();
            this.m_rectGuide = this.GetComponent<RectGuide>();
            this.m_canvas = transform.parent.GetComponent<Canvas>();
            this.InitSteps();
        }

        #region 引导步骤处理
        /// <summary>
        /// 初始化引导步骤
        /// </summary>
        void InitSteps()
        {
            m_AllSteps = new BaseStep[this.transform.childCount];
            for (int i = 0; i < this.transform.childCount; i++)
            {
                this.m_AllSteps[i] = this.transform.GetChild(i).GetComponent<BaseStep>();
            }
        }

        void OnStoryEnd(object param)
        {
            MsgDispatcher.UnRegister(GuideMessage.GuideStoryEnd, this.OnStoryEnd);
            this.m_maskImg.enabled = true;
            this.NextStep(SonGuideStepType.ClickGesture);
        }

        /// <summary>
        /// 执行步骤
        /// </summary>
        private void Excuete()
        {
            this.m_hasexcuted = true;
            this.gameObject.Show();
            this.HideAllSteps();
            this.m_AllSteps[m_currentStepIndex].ExcuteStep(this.m_canvas);
            this.m_currentStepIndex++;
        }

        /// <summary>
        /// 执行步骤
        /// </summary>
        private void ExcuteStep(int stepIndex)
        {
            this.m_currentStepIndex = stepIndex;
            if (stepIndex > -1 && stepIndex < this.m_AllSteps.Length)
            {
                this.m_hasexcuted = false;
                Invoke("Excuete", this.m_AllSteps[this.m_currentStepIndex].m_delayTime);
            }
        }

        /// <summary>
        /// 进入下一步
        /// </summary>
        public void NextStep(SonGuideStepType stepType)
        {
            if (!this.m_hasexcuted) return;

            if (this.m_currentStepIndex > this.m_AllSteps.Length - 1 || stepType == SonGuideStepType.StepOver)
            {
                m_OnFinished?.Invoke();
                return;
            }

            if (stepType == this.m_AllSteps[this.m_currentStepIndex].m_StepType)
            {
                this.ExcuteStep(this.m_currentStepIndex);
            }
            else
            {
                m_OnFinished?.Invoke();
                MyDebuger.LogError("步骤不对 当前要执行的步骤为:" + stepType + " 正在执行的步骤为 " + this.m_AllSteps[this.m_currentStepIndex].m_StepType);
            }
        }


        /// <summary>
        /// 隐藏所有步骤
        /// </summary>
        private void HideAllSteps()
        {
            for (int i = 0; i < this.m_AllSteps.Length; i++)
            {
                this.m_AllSteps[i].Hide();
            }
        }
        #endregion


        #region 引导显示部分

        /// <summary>
        /// 引导公有部分
        /// </summary>
        /// <param name="target"></param>
        /// <param name="guideType"></param>
        private void Guide(RectTransform target, GuideType guideType)
        {
            this.m_targetRect = target;
            this.m_currentGuideType = guideType;
            switch (guideType)
            {
                case GuideType.Rect:
                    this.m_maskImg.material = this.m_rectMat;
                    break;
                case GuideType.Cycle:
                    this.m_maskImg.material = this.m_cycleMat;
                    break;
                default:
                    MyDebuger.LogError("can not found guidtype " + guideType);
                    break;
            }
        }

        /// <summary>
        /// 引导
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="target">引导目标</param>
        /// <param name="guideType">引导提示形状</param>
        public void Guide(Canvas canvas, RectTransform target, GuideType guideType, TranslateType translateType = TranslateType.Direct, float centertime = 1)
        {
            this.Guide(target, guideType);
            switch (guideType)
            {
                case GuideType.Rect:
                    this.m_rectGuide.Guide(canvas, target);
                    break;
                case GuideType.Cycle:
                    this.m_cycleGuide.Guide(canvas, target);
                    break;
                default:
                    MyDebuger.LogError("can not found guidtype " + guideType);
                    break;
            }
        }


        /// <summary>
        /// 引导动画
        /// </summary>
        /// <param name="canvas"></param>
        /// <param name="target">引导目标</param>
        /// <param name="guideType">引导提示形状</param>
        public void Guide(Canvas canvas, RectTransform target, GuideType guideType, float scal, float scaltime, TranslateType translateType = TranslateType.Direct, float centertime = 1)
        {
            this.Guide(target, guideType);
            switch (guideType)
            {
                case GuideType.Rect:
                    this.m_rectGuide.Guide(canvas, target, scal, scaltime, translateType, centertime);
                    break;
                case GuideType.Cycle:
                    this.m_cycleGuide.Guide(canvas, target, scal, scaltime, translateType, centertime);
                    break;
                default:
                    MyDebuger.LogError("can not found guidtype " + guideType);
                    break;
            }
        }

        /// <summary>
        /// 是否可以渗透事件
        /// </summary>
        /// <param name="sp"></param>
        /// <param name="eventCamera"></param>
        /// <returns>false 可以渗透事件 true 不可以渗透事件</returns>
        public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
        {
            if (m_targetRect == null) return false;
            ///是否点击到目标物体
            bool ispointtargetRect = RectTransformUtility.RectangleContainsScreenPoint(m_targetRect, sp, eventCamera);
            return !ispointtargetRect;
        }

        #endregion
    }
}
